package com.umeox.watch.moto.dataservice.db.model;


import com.umeox.moto.common.utils.DateUtils;
import com.umeox.watch.moto.dataservice.utils.Utils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

public class ForbidPeriods {
    private List<ForbidPeriod> classTimeList;

    public List<ForbidPeriod> getClassTimeList() {
        return classTimeList;
    }

    public void setClassTimeList(List<ForbidPeriod> classTimeList) {
        this.classTimeList = classTimeList;
    }

    public boolean isAvalid() {
        return getClassTimeList() != null && !getClassTimeList().isEmpty();
    }

    /**
     * 根据周期把所有时段解析成具体的时间
     * 例如有设置一个时段 08:30-10:30   每周一到周五重复 0111110 的禁用时段 , 当前日期为2017-9-15 星期五
     * 那么就会解析两个ForbidPeriod对象(当天和下一天)，
     * 第一个ForbidPeriod{startTimeInMillis=2017-09-15 08:30:00的时间戳, endTimeInMillis=2017-09-15 10:30:00的时间戳}
     * 第二个ForbidPeriod{startTimeInMillis=2017-09-18 08:30:00的时间戳, endTimeInMillis=2017-09-18 10:30:00的时间戳}
     */
    public List<Period> getPeriods() {
        List<Period> forbidPeriods = new ArrayList<>();
        for (ForbidPeriod period : getClassTimeList()) {
            List<Period> temp = getForbidPeriod(period.getTimePeriod(), period.getRepeatExpression());
            if (temp != null && !temp.isEmpty()) {
                forbidPeriods.addAll(temp);
            }
        }
        return forbidPeriods;
    }

    /**
     * 根据时间段和周期获取当天和下一天的具体开始和结束时间
     *
     * @param sec 时间段，24小时制 HH:mm
     * @param exp 重复周期，正确格式：1100011  7个字节长度，只允许0或者1
     */
    private List<Period> getForbidPeriod(String sec, String exp) {
        if (!Utils.isInvalidPeriod(sec)
                || !Utils.isInvalidRepeatExpression(exp)) {
            return new ArrayList<>(0);
        }

        List<Period> forbidPeriods = null;
        if (!"0000000".equalsIgnoreCase(exp)) {

            char[] c = exp.toCharArray();
            forbidPeriods = new ArrayList<Period>();

            String[] period = Utils.parsePeriod(sec);
            int hourOfDay2Enable = Integer.parseInt(period[0]);
            int minute2Enable = Integer.parseInt(period[1]);
            int hourOfDay2Disable = Integer.parseInt(period[2]);
            int minute2Disable = Integer.parseInt(period[3]);

            Calendar calendarDayOfWeek = Calendar.getInstance();
            calendarDayOfWeek.set(Calendar.SECOND, 0);
            calendarDayOfWeek.set(Calendar.MILLISECOND, 0);

            /**
             *因为要记录当天和下一天具体开始和结束时间，所以用一个count标记 calendarDayOfWeek 是否有加 1
             * calendarDayOfWeek + n 表示已经是下一个周期了，我们这里是需要当前和下一个周期的禁用时段，所以
             * 判断到calendarDayOfWeek有累加就可以结束迭代了
             */
            int count = 0;
            while (count < 7) {
                int currentDayOfWeek = calendarDayOfWeek.get(Calendar.DAY_OF_WEEK);
                if ("1".equals(String.valueOf(c[currentDayOfWeek - 1]))) {

                    Period forbidPeriod = new Period();

                    calendarDayOfWeek.set(Calendar.HOUR_OF_DAY, hourOfDay2Enable);
                    calendarDayOfWeek.set(Calendar.MINUTE, minute2Enable);
                    forbidPeriod.setStartTimeInMillis(calendarDayOfWeek.getTimeInMillis());

                    calendarDayOfWeek.set(Calendar.HOUR_OF_DAY, hourOfDay2Disable);
                    calendarDayOfWeek.set(Calendar.MINUTE, minute2Disable);
                    forbidPeriod.setEndTimeInMillis(calendarDayOfWeek.getTimeInMillis());

                    forbidPeriods.add(forbidPeriod);
                    if (count > 0) {
                        break;
                    }
                }
                //如果运行到这里，表示当天不在重复周期中，日期加一天
                calendarDayOfWeek.add(Calendar.DAY_OF_MONTH, 1);
                count++;
            }
        }
        return forbidPeriods;
    }

    private Calendar getEnable(String sec) {
        if (!Utils.isInvalidPeriod(sec)) {
            return null;
        }
        String[] amClassTime = Utils.parsePeriod(sec);
        Calendar now = Calendar.getInstance();
        int hourOfDay4Enable = Integer.parseInt(amClassTime[0]);
        int minute4Enable = Integer.parseInt(amClassTime[1]);
        now.set(Calendar.HOUR_OF_DAY, hourOfDay4Enable);
        now.set(Calendar.MINUTE, minute4Enable);
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);
        return now;
    }

    private Calendar getDisable(String sec) {
        if (!Utils.isInvalidPeriod(sec)) {
            return null;
        }
        String[] amClassTime = Utils.parsePeriod(sec);
        Calendar now = Calendar.getInstance();
        int hourOfDay4Disable = Integer.parseInt(amClassTime[2]);
        int minute4Disable = Integer.parseInt(amClassTime[3]);
        now.set(Calendar.HOUR_OF_DAY, hourOfDay4Disable);
        now.set(Calendar.MINUTE, minute4Disable);
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);
        return now;
    }

    public boolean enableNow() {
        Calendar now = Calendar.getInstance();
        for (ForbidPeriod period : getClassTimeList()) {
            char[] c = period.getRepeatExpression().toCharArray();
            int currentDayOfWeek = now.get(Calendar.DAY_OF_WEEK);
            if ("1".equals(String.valueOf(c[currentDayOfWeek - 1]))) {
                Calendar enable = getEnable(period.getTimePeriod());
                Calendar disable = getDisable(period.getTimePeriod());
                if (enable != null && disable != null
                        && now.compareTo(enable) >= 0 && now.compareTo(disable) <= 0) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return "ForbidPeriods{" +
                "classTimeList=" + classTimeList +
                '}';
    }

    public class Period implements Comparable<Period> {
        private long startTimeInMillis;
        private long endTimeInMillis;

        public long getStartTimeInMillis() {
            return startTimeInMillis;
        }

        public Period setStartTimeInMillis(long startTimeInMillis) {
            this.startTimeInMillis = startTimeInMillis;
            return this;
        }

        public long getEndTimeInMillis() {
            return endTimeInMillis;
        }

        public Period setEndTimeInMillis(long endTimeInMillis) {
            this.endTimeInMillis = endTimeInMillis;
            return this;
        }

        @Override
        public int compareTo(Period another) {
            if (another == null) {
                throw new NullPointerException("anotherCalendar == null");
            }
            //根据时段开始时间升序排列
            long timeToStart = getStartTimeInMillis();
            long anotherTimeToStart = another.getStartTimeInMillis();
            if (timeToStart > anotherTimeToStart) {
                return 1;
            }
            if (timeToStart == anotherTimeToStart) {
                return 0;
            }
            return -1;
        }

        @Override
        public String toString() {
            return "{" + "startTimeInMillis=" + DateUtils.formatDateTime(startTimeInMillis) + ", endTimeInMillis=" + DateUtils.formatDateTime(endTimeInMillis) + "}";
        }
    }
}
